use crate::common::{Digital, OneInputElectric};
use crate::output::State::{ONE, ZERO};
use crate::output::{DigitalState, State};
use std::rc::Rc;
use crate::Digital1Line;

#[allow(unused)]
///NotElectric structure represent the NOT logic circuit
pub struct NotElectric {
    input_a: Option<Rc<dyn Digital1Line>>,
    input_a_state: DigitalState,
    output_state: DigitalState,
    times: usize,
}
#[allow(unused)]
impl Digital1Line for NotElectric{}
#[allow(unused)]
impl Digital for NotElectric {
    fn get_output(&self) -> DigitalState {
        self.output_state.clone()
    }
}

impl NotElectric {
    ///This function stands for handling a Not gate logic operation
    pub fn process(input: Option<Rc<dyn Digital1Line>>) -> Rc<Self> {
        match input {
            Some(a) => {
                let input_a_states = a.get_digital_output();
                let input_a_state = input_a_states.output_line_x(0);
                let output_state = input_a_state
                    .into_iter()
                    .map(|a_state| Self::process_single_input(a_state))
                    .collect::<Vec<_>>();
                let output_states = DigitalState::new(vec![output_state.clone()], 1, output_state.len());
                let times = output_states.per_line_signals_count();
                Rc::new(NotElectric::new(
                    Some(a.clone()),
                    input_a_states,
                    output_states,
                    times,
                ))
            }
            None => {
                let output_state = DigitalState::new(vec![vec![]], 1, 0);
                let input_a = None;
                let input_a_state = DigitalState::new(vec![vec![]], 1, 0);
                Rc::new(NotElectric::new(input_a, input_a_state, output_state, 0))
            }
        }
    }
    fn process_single_input(a_state: Option<State>) -> Option<State> {
        if let Some(a) = a_state {
            if a == ONE { Some(ZERO) } else { Some(ONE) }
        } else {
            None
        }
    }
}

#[allow(unused)]
impl OneInputElectric for NotElectric {
    fn set_input(&self, input: Option<Rc<dyn Digital1Line>>) -> Rc<Self> {
        Self::process(input)
    }
}
impl NotElectric {
    pub fn new(
        input_a: Option<Rc<dyn Digital1Line>>,
        input_a_state: DigitalState,
        output_state: DigitalState,
        times: usize,
    ) -> Self {
        Self {
            input_a,
            input_a_state,
            output_state,
            times,
        }
    }

    pub fn input_a(&self) -> Option<Rc<dyn Digital1Line>> {
        self.input_a.clone()
    }

    pub fn input_a_state(&self) -> DigitalState {
        self.input_a_state.clone()
    }

    pub fn output_state(&self) -> DigitalState {
        self.output_state.clone()
    }

    pub fn times(&self) -> usize {
        self.times
    }
}
